package net.oschina.git.fsppp.model;


import net.oschina.git.fsppp.exception.P3Exception;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

/**
 * 文件分配表
 */
public class P3FAT {
    /**
     * disk: String
     * 磁盘名
     */
    private String disk;
    /**
     * content: Byte
     * 文件分配表内容
     */
    private Byte[] content;

    public String getDisk() {
        return disk;
    }

    public void setDisk(String disk) {
        this.disk = disk;
    }

    public Byte[] getContent() {
        return content;
    }

    public void setContent(Byte[] content) {
        this.content = content;
    }

    public void initFat() {
        content = new Byte[128];
        content[0] = -1;
        content[1] = -1;
        for (int i=2;i<128;i++) {
            content[i] = 0;
        }
    }

    /**
     * 根据fat 生成文件块号链接
     * 2-3-4
     * 6-7
     * ...
     * @return
     */
    public List<LinkedList<Integer>> toFileLinked() {
        List<LinkedList<Integer>> fileLinks = new ArrayList<>();
        LinkedList<Boolean> isRead = new LinkedList<>();//记录是否读取过这一块
        for (int i = 0; i < 128; i++) {
            isRead.add(Boolean.FALSE);
        }
        for (int i=2;i<128;i++) {
            if (content[i] > 0) {
                int head = getIndex((byte) i);
                int outHead = 0;
                if (head == 0) {
                    outHead = i;
                }
                while (head != 0) {
                    outHead = head;
                    head = getIndex((byte) head);
                }
                int j = outHead;
                LinkedList<Integer> l = new LinkedList<>();
                do {
                    if (!isRead.get(j)) {
                        l.add(j);
                        isRead.set(j, Boolean.TRUE);
                    }
                    j = content[j];
                } while (j != -1);
                if (l.size() > 0) {
                    fileLinks.add(l);
                }
            }
        }
        for (int i=2;i<128;i++) {
            if (content[i] == -1) {
                if (!isRead.get(i)) {
                    LinkedList<Integer> l = new LinkedList<>();
                    l.add(i);
                    isRead.set(i, Boolean.TRUE);
                    fileLinks.add(l);
                }
            }
        }
        return fileLinks;
    }
    /**
     * 根据fat 生成 startNum 文件块号链接
     * @return
     */
    public LinkedList<Integer> getFileLink(int startNum) {
        LinkedList<Integer> ids = new LinkedList<>();
        int index = startNum;
        while (this.content[index] != -1) {
            ids.add(index);
            index = this.content[index];
        }
        ids.add(index);
        return ids;
    }

    /**
     * 获取内容相同坐标
     * @param b
     * @return
     */
    public int getIndex(byte b) {
        for (int j = 2; j < 128; j++) {
            if (content[j] == b) {
                return j;
            }
        }
        return 0;
    }

    /**
     * 根据fat 生成文件夹块号链接
     * 2
     * 3
     * 4
     * 6
     * ...
     * @return
     */
    public List<Integer> toDirLinked() {
        List<LinkedList<Integer>> fileLinks = this.toFileLinked();
        List<Integer> ids = new ArrayList<>(fileLinks.size());
        fileLinks.stream().filter(v -> v.size() == 1).forEach(v -> ids.add(v.get(0)));//过滤出文件（夹）
        return ids;
    }
    /**
     * 根据fat 生成文件块号链接
     * 2,5,6
     * 3,8
     * 7,12,15
     * ...
     * @return
     */
    public List<LinkedList<Integer>> toDirFileLinked() {
        List<LinkedList<Integer>> fileLinks = this.toFileLinked();
        List<LinkedList<Integer>> idlinks = new ArrayList<>(fileLinks.size());
        fileLinks.stream().filter(v -> v.size() > 1).forEach(v -> idlinks.add(v));//过滤出文件（夹）
        return idlinks;
    }



    /**
     * 分配给文件夹
     * @return
     */
    public int allocate() {
        for (int i = 2; i < 128; i++) {
            if (this.content[i] == 0) {
                content[i] = -1;
                return i;
            }
        }
        throw new P3Exception("内存不足！");
    }
    @Override
    public int hashCode() {
        int hash = 17;

        if (this.content != null) {
            hash = hash * 31 + this.content.hashCode();
        }

        return hash;
    }

    public void release(Integer[] ids) {
        for (int i = 0; i<ids.length;i++) {
            this.content[ids[i]] = 0;
        }
    }
}
